"""哈哩哈哩异步操作下载，适用于无加密的视频，直接根据m3u8文件中的顺序进行下载拼接"""
import asyncio
import os
import sys
from typing import List

import aiofiles
import aiohttp
import requests

# 配置参数 - 统一管理便于修改
CONFIG = {
    "url": "https://vip.ffzy-play2.com/20221213/8239_69f974bd/2000k/hls/mixed.m3u8",
    "output_filename": "约战S4p3.mp4",
    "output_directory": "E:/T/Videos",
    "temp_directory": "../数据暂存",
    "m3u8_filename": "m3u8.txt"
}
error_list: List[str] = []


def get_m3u8(url: str) -> None:
    """获取m3u8文件并保存"""
    res = requests.get(url)
    m3u8_path = os.path.join(CONFIG["temp_directory"], CONFIG["m3u8_filename"])
    with open(m3u8_path, "wb") as f:
        f.write(res.content)
    print("获取m3u8文件成功")


async def download(url, name, session):
    """下载单个ts文件"""
    name1 = name[-7:]

    head = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"}
    while True:
        try:
            async with session.get(url, headers=head) as resp:
                if resp.status != 200:
                    print("无响应", url)
                    raise
                async with aiofiles.open(f"../数据暂存/{name1}", "wb") as f1:
                    await f1.write(await resp.content.read())
            print(f"{name1}下载完成")
            break
        except Exception as e:
            print(f"{name1}下载出现异常", e)
            error_list.append(url)
            break  # 避免无限循环


async def download_start(url):
    """开始下载所有ts文件"""
    tasks = []
    m3u8_path = os.path.join(CONFIG["temp_directory"], CONFIG["m3u8_filename"])
    async with aiohttp.ClientSession() as session:
        async with aiofiles.open(m3u8_path, "r", encoding="utf-8") as file:
            async for line in file:
                line: str
                line = line.strip()
                # 跳过注释行和空行
                if line.startswith("#") or not line:
                    continue
                else:
                    ts_url = url.replace("mixed.m3u8", "") + line
                    task = asyncio.create_task(download(ts_url, line, session))
                    tasks.append(task)

            print(f"创建了 {len(tasks)} 个下载任务")

            # 检查是否有任务需要执行
            if tasks:
                await asyncio.wait(tasks)
            else:
                print("警告：没有找到有效的TS文件链接，无法创建下载任务")


def retry_failed_downloads() -> None:
    """重新下载失败的文件"""
    print("----尝试重新下载----")
    for i in error_list:
        name = i[-6:]
        file_path = f"{CONFIG['temp_directory']}/{name}"
        with open(file_path, "wb") as f:
            while True:
                try:
                    res = requests.get(i)
                    f.write(res.content)
                    break
                except Exception as e:
                    print("再次出现错误：", e)

        print(f"————————{name}重新下载完毕——————")


def merge(name):
    """合并所有ts文件"""
    lst = []
    m3u8_path = os.path.join(CONFIG["temp_directory"], CONFIG["m3u8_filename"])
    with open(m3u8_path, "r", encoding="utf-8") as file:
        for line in file:
            if line.startswith("#") or not line:
                continue
            name1 = line.strip()[-7:]
            lst.append(name1)
    if not lst:
        print("没有文件需要合并")
        return

    s = "+".join(lst)
    os.chdir(CONFIG["temp_directory"])
    os.system(f"copy /b {s} {name}")
    os.system(f'move "{name}" "{CONFIG["output_directory"]}"')
    # 删除暂存数据
    os.system("del *.ts")
    os.system("del *.txt")


# 修复Windows平台asyncio问题
async def main_async() -> None:
    """异步主函数"""
    # 获取m3u8，并保存
    get_m3u8(CONFIG["url"])

    # 异步下载
    await download_start(CONFIG["url"])

    # 重新下载失败的文件
    if error_list:
        retry_failed_downloads()

    print("全部下载完成")
    merge(CONFIG["output_filename"])
    print("==========合并完成!==========")


def main() -> None:
    """主函数"""
    if sys.platform.startswith("win"):
        # Windows平台特殊处理
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

    asyncio.run(main_async())


if __name__ == '__main__':
    main()
